#include "widgets/button.h"
#include "system/window.h"
#include "graphics/sprite_events.h"
#include "graphics/sprite_events_private.h"
#include "devices/mouse.h"

void _esdlBlitText(EsdlButton * button) {
    if (button == NULL || button->textFont == NULL || button->text == NULL) {
        return;
    }

    int w = 0, h = 0;
    TTF_SizeText(button->textFont, button->text, &w, &h);

    esdlDrawAntiAliasedText(button->sprite,
            button->text,
            (button->sprite->surface->w - w) / 2,
            (button->sprite->surface->h / 3 - h) / 2,
            button->textFont,
            button->textColor);
    esdlDrawAntiAliasedText(button->sprite, 
            button->text,
            (button->sprite->surface->w - w) / 2, 
            button->sprite->surface->h / 3 + (button->sprite->surface->h / 3 - h) / 2, 
            button->textFont, 
            button->textColor);
    esdlDrawAntiAliasedText(button->sprite, 
            button->text, 
            (button->sprite->surface->w - w) / 2,
            2 * button->sprite->surface->h / 3 + (button->sprite->surface->h / 3 - h) / 2, 
            button->textFont, 
            button->textColor);
}

void _esdlGenerateButtonSurface(EsdlButton* button) {
    SDL_BlitSurface(button->backgroundSurface, NULL, button->sprite->surface, NULL);
    _esdlBlitText(button);
}

void _esdlButtonEnter(EsdlEvent* event) {
    EsdlButton* button = (EsdlButton*) event->sprite->data;

    if (!esdlIsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
        button->sprite->visiblePart.y = button->sprite->surface->h / 3;
    } else {
        button->sprite->visiblePart.y = 2 * button->sprite->surface->h / 3;
    }
}

void _esdlButtonLeave(EsdlEvent* event) {
    EsdlButton* button = (EsdlButton*) event->sprite->data;
    button->sprite->visiblePart.y = 0;
}

void _esdlButtonDown(EsdlEvent* event) {
    if (esdlIsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
        EsdlButton * button = (EsdlButton *) event->sprite->data;
        button->sprite->visiblePart.y = 2 * button->sprite->surface->h / 3;
    }
}

void _esdlButtonUp(EsdlEvent* event) {
    EsdlButton * b = (EsdlButton *) event->sprite->data;
    b->sprite->visiblePart.y = b->sprite->surface->h / 3;
    if (b->callback != NULL && esdlGetMouseButton(event) == MOUSE_BUTTON_LEFT) {
        b->callback(event);
    }
}

EsdlButton* esdlCreateButton(const char* text, unsigned int x, unsigned int y, unsigned int width, unsigned int height, EsdlEventCallback callback) {
    EsdlButton* button = malloc(sizeof(EsdlButton));
    button->text = malloc((strlen(text)+1) * sizeof(char));
    strcpy(button->text, text);
    button->callback = callback;

    button->backgroundSurface = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, 3 * height, 32, 0, 0, 0, 0);
    button->backgroundImage = NULL;

    button->sprite = esdlCreateSprite(width, 3 * height);
    button->sprite->visiblePart.h = height;
    esdlSetSpritePosition(button->sprite, x, y);
    button->sprite->data = button;

    button->textFont = NULL;

    // Cas : enter and mouse button down
    esdlAddListener(button->sprite, ON_MOUSE_ENTER, _esdlButtonEnter, true);
    esdlAddListener(button->sprite, ON_MOUSE_LEAVE, _esdlButtonLeave, true);
    esdlAddListener(button->sprite, ON_MOUSE_DOWN, _esdlButtonDown, true);
    esdlAddListener(button->sprite, ON_MOUSE_UP, _esdlButtonUp, true);

    _esdlGenerateButtonSurface(button);

    return button;
}

EsdlButton* esdlCreateButtonFromImageFile(const char* path, unsigned int x, unsigned int y, EsdlEventCallback callback) {
    EsdlButton* button = NULL;
    button = malloc(sizeof(EsdlButton));
    button->text = NULL;
    button->callback = callback;

    button->backgroundSurface = NULL;
    button->backgroundSurface = IMG_Load(path);
    button->backgroundImage = NULL;

    if (button->backgroundSurface == NULL) {
        free(button);
        return NULL;
    }

    button->sprite = esdlCreateSprite(button->backgroundSurface->w, button->backgroundSurface->h);
    button->sprite->visiblePart.h = button->backgroundSurface->h / 3;
    esdlSetSpritePosition(button->sprite, x, y);
    button->sprite->data = button;

    button->textFont = NULL;

    // Cas : enter and mouse button down
    esdlAddListener(button->sprite, ON_MOUSE_ENTER, _esdlButtonEnter, true);
    esdlAddListener(button->sprite, ON_MOUSE_LEAVE, _esdlButtonLeave, true);
    esdlAddListener(button->sprite, ON_MOUSE_DOWN, _esdlButtonDown, true);
    esdlAddListener(button->sprite, ON_MOUSE_UP, _esdlButtonUp, true);

    _esdlGenerateButtonSurface(button);

    return button;
}

EsdlButton * esdlCreateButtonFromImage(EsdlImage * image, unsigned int x, unsigned int y, EsdlEventCallback callback) {
        EsdlButton * button;
        button = malloc(sizeof * button);
        button->text = NULL;
        button->callback = callback;
	
        button->backgroundImage = image;
        button->backgroundSurface = button->backgroundImage->surface;
	
        if(button->backgroundSurface == NULL) {
                free(button);
                return NULL;
        }
	
        button->sprite = esdlCreateSprite(button->backgroundSurface->w, button->backgroundSurface->h);
        button->sprite->visiblePart.h = button->backgroundSurface->h/3;
        esdlSetSpritePosition(button->sprite, x, y);
        button->sprite->data = button;
	
        button->textFont = NULL;
	
        // Cas : enter and mouse button down
        esdlAddListener(button->sprite, ON_MOUSE_ENTER, _esdlButtonEnter, true);
        esdlAddListener(button->sprite, ON_MOUSE_LEAVE, _esdlButtonLeave, true);
        esdlAddListener(button->sprite, ON_MOUSE_DOWN, _esdlButtonDown, true);
        esdlAddListener(button->sprite, ON_MOUSE_UP, _esdlButtonUp, true);
	
        _esdlGenerateButtonSurface(button);
	
        return button;
}

void esdlDeleteButton(EsdlButton* button) {

    esdlDeleteSprite(button->sprite);
    button->sprite = NULL;
    if(button->backgroundImage == NULL) SDL_FreeSurface(button->backgroundSurface);
    free(button);
}

void esdlSetButtonText(EsdlButton* button, const char* text) {
    if(button->text != NULL) free(button->text);
    button->text = malloc((strlen(text)+1) * sizeof(char));
    strcpy(button->text, text);
    _esdlGenerateButtonSurface(button);
}

void esdlSetButtonTextFont(EsdlButton* button, EsdlFont* font) {
    button->textFont = font;
    _esdlGenerateButtonSurface(button);
}

void esdlSetButtonTextColor(EsdlButton* button, EsdlColor color) {
    button->textColor.r = color.r;
    button->textColor.g = color.g;
    button->textColor.b = color.b;
    _esdlGenerateButtonSurface(button);
}

void esdlSetBackgroundColorUp(EsdlButton* button, EsdlColor color) {
    SDL_Rect rect;
    rect.x = 0;
    rect.y = 0;
    rect.w = button->backgroundSurface->w;
    rect.h = button->backgroundSurface->h / 3;
    SDL_FillRect(button->backgroundSurface, &rect, SDL_MapRGB(button->backgroundSurface->format, color.r, color.g, color.b));
    _esdlGenerateButtonSurface(button);
}

void esdlSetBackgroundColorDown(EsdlButton* button, EsdlColor color) {
    SDL_Rect rect;
    rect.x = 0;
    rect.y = 2 * button->backgroundSurface->h / 3;
    rect.w = button->backgroundSurface->w;
    rect.h = button->backgroundSurface->h / 3;
    SDL_FillRect(button->backgroundSurface, &rect, SDL_MapRGB(button->backgroundSurface->format, color.r, color.g, color.b));
    _esdlGenerateButtonSurface(button);
}

void esdlSetBackgroundColorHover(EsdlButton* button, EsdlColor color) {
    SDL_Rect rect;
    rect.x = 0;
    rect.y = button->backgroundSurface->h / 3;
    rect.w = button->backgroundSurface->w;
    rect.h = button->backgroundSurface->h / 3;
    SDL_FillRect(button->backgroundSurface, &rect, SDL_MapRGB(button->backgroundSurface->format, color.r, color.g, color.b));
    _esdlGenerateButtonSurface(button);
}

EsdlSprite* esdlGetSpriteFromButton(EsdlButton* button) {
    return button->sprite;
}

void esdlShowButton(EsdlButton* button) {
    button->sprite->show = true;
}

void esdlHideButton(EsdlButton* button) {
    button->sprite->show = false;
}

void esdlToggleButtonVisibility(EsdlButton* button) {
    button->sprite->show = (button->sprite->show ? false : true);
}